package cn.huanzi.qch.springbootmybatis.service;

import cn.huanzi.qch.springbootmybatis.constant.Constant;
import cn.huanzi.qch.springbootmybatis.mapper.MysqlBackupsMapper;
import cn.huanzi.qch.springbootmybatis.model.ErrorTip;
import cn.huanzi.qch.springbootmybatis.model.MysqlBackups;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @author keven
 * @date 2023-02-10 10:48 上午
 * @Description
 */
@Service
@Slf4j
public class MysqlBackupsServiceImpl implements MysqlBackupsService{

    @Resource
    private MysqlBackupsMapper mysqlBackupsDao;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public MysqlBackups queryById(Integer id) {
        return this.mysqlBackupsDao.queryById(id);
    }

    /**
     * 分页查询
     *
     * @param mysqlBackups 筛选条件
     * @param pageRequest  分页对象
     * @return 查询结果
     */
    @Override
    public Page<MysqlBackups> queryByPage(MysqlBackups mysqlBackups, PageRequest pageRequest) {
        long total = this.mysqlBackupsDao.count(mysqlBackups);
        return new PageImpl<>(this.mysqlBackupsDao.queryAllByLimit(mysqlBackups, pageRequest), pageRequest, total);
    }

    /**
     * 新增数据
     *
     * @param mysqlBackups 实例对象
     * @return 实例对象
     */
    @Override
    public MysqlBackups insert(MysqlBackups mysqlBackups) {
        this.mysqlBackupsDao.insert(mysqlBackups);
        return mysqlBackups;
    }

    /**
     * 修改数据
     *
     * @param mysqlBackups 实例对象
     * @return 实例对象
     */
    @Override
    public MysqlBackups update(MysqlBackups mysqlBackups) {
        this.mysqlBackupsDao.update(mysqlBackups);
        return this.queryById(mysqlBackups.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.mysqlBackupsDao.deleteById(id) > 0;
    }

    @Override
    public List<MysqlBackups> selectBackupsList() {
        return mysqlBackupsDao.selectBackupsList();
    }

    @Override
    public Object mysqlBackups(String filePath, String url, String userName, String password) {
        // 获取ip
        final String ip = url.substring(13, 26);
        System.out.println(ip);
        // 获取端口号
        final String port = url.substring(27, 31);
        System.out.println(port);
        // 获取数据库名称
        final String database_name = url.substring(32, 50);
        System.out.println(database_name);
        // 数据库文件名称
        StringBuilder mysqlFileName = new StringBuilder()
                .append(Constant.DATA_BASE_NAME)
                .append("_")
                .append(DateUtil.format(new Date(), "yyyy-MM-dd-HH-mm-ss"))
                .append(Constant.FILE_SUFFIX);
        // 备份命令
        StringBuilder cmd = new StringBuilder()
                .append("mysqldump ")
                .append("--no-tablespaces ")
                .append("-h")
                .append(ip)
                .append(" -u")
                .append(userName)
                .append(" -p")
                .append(password)
                // 排除MySQL备份表
                .append(" --ignore-table ")
                .append(database_name)
                .append(".mysql_backups ")
                .append(database_name)
                .append(" > ")
                .append(filePath)
                .append(mysqlFileName);


        log.info("执行cmd命令：" + cmd);
        // 判断文件是否保存成功
        if (!FileUtil.exist(filePath)) {
            FileUtil.mkdir(filePath);
            return new ErrorTip(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE.value(), "备份失败，文件保存异常，请查看文件内容后重新尝试！");
        }
        // 获取操作系统名称
        String osName = System.getProperty("os.name").toLowerCase();
        String[] command = new String[0];
        if (Constant.isSystem(osName)) {
            // Windows
            command = new String[]{"cmd", "/c", String.valueOf(cmd)};
        } else {
            // Linux
            command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)};
        }
        MysqlBackups smb = new MysqlBackups();
        // 备份信息存放到数据库
        smb.setMysqlIp(ip);
        smb.setMysqlPort(port);
        smb.setBackupsName(String.valueOf(mysqlFileName));
        smb.setDatabaseName(database_name);
        smb.setMysqlCmd(String.valueOf(cmd));
        smb.setBackupsPath(filePath);
        smb.setCreateTime(DateTime.now());
        smb.setStatus(1);
        smb.setOperation(0);
        mysqlBackupsDao.insert(smb);
        log.error("数据库备份命令为：{}", cmd);
        // 获取Runtime实例
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(command);
            if (process.waitFor() == 0) {
                log.info("Mysql 数据库备份成功,备份文件名：{}", mysqlFileName);
            } else {
                return new ErrorTip(HttpStatus.INTERNAL_SERVER_ERROR.value(), "网络异常，数据库备份失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ErrorTip(HttpStatus.INTERNAL_SERVER_ERROR.value(), "网络异常，数据库备份失败");
        }
        return smb;
    }

    @Override
    public MysqlBackups selectListId(Long id) {
        return mysqlBackupsDao.selectListId(id);
    }

    @Override
    public Object rollback(MysqlBackups smb, String userName, String password) {
        // 备份路径和文件名
        StringBuilder realFilePath = new StringBuilder().append(smb.getBackupsPath()).append(smb.getBackupsName());
        if (!FileUtil.exist(String.valueOf(realFilePath))) {
            return new ErrorTip(HttpStatus.NOT_FOUND.value(), "文件不存在，恢复失败，请查看目录内文件是否存在后重新尝试！");
        }
        StringBuilder cmd = new StringBuilder()
                .append("mysql -h")
                .append(smb.getMysqlIp())
                .append(" -u")
                .append(userName)
                .append(" -p")
                .append(password)
                .append(" ")
                .append(smb.getDatabaseName())
                .append(" < ")
                .append(realFilePath);
        String[] command = new String[0];
        log.error("数据库恢复命令为：{}", cmd);
        // 获取操作系统名称
        String osName = System.getProperty("os.name").toLowerCase();
        if (Constant.isSystem(osName)) {
            // Windows
            command = new String[]{"cmd", "/c", String.valueOf(cmd)};
        } else {
            // Linux
            command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)};
        }
        // 恢复指令写入到数据库
        smb.setMysqlBackCmd(String.valueOf(cmd));
        // 更新操作次数
        smb.setRecoveryTime(DateTime.now());
        smb.setOperation(smb.getOperation() + 1);
        // 获取Runtime实例
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(command);
            if (process.waitFor() == 0) {
                log.error("Mysql 数据库恢复成功,恢复文件名：{}", realFilePath);
            } else {
                return new ErrorTip(HttpStatus.GATEWAY_TIMEOUT.value(), "网络异常，恢复失败，请稍后重新尝试！");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ErrorTip(HttpStatus.GATEWAY_TIMEOUT.value(), "网络异常，恢复失败，请稍后重新尝试！");
        }
        return smb;
    }
}

